import datetime
import json
import logging
import re
import time
from decimal import Decimal

import pymongo

from sqlalchemy import and_, extract, func, or_

from base.connection import mongodb_util, redis_util
from base.request import ApiBaseHandler
from common.definition import (
    ret_msg,
)
from conf import config, promotion
from conf.config import DOMAIN, HOST_NAME
from helper.api_helper import ApiHelper
from helper.user import AddressHelper, UserHelper

logger = logging.getLogger(__name__)


class Mall(ApiBaseHandler):
    def data_received(self, chunk):
        pass

    def get_imgs(self, nums):
        class Goods(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_goods", "model": Goods},
            ]
        )
        goods_list = (
            session.query(Goods)
            .filter_by(
                sdef_goods_status=1,
                sdef_goods_is_delete=0,
                sdef_goods_factory_uid=config.FACTORY_UID,
            )
            .order_by(Goods.sdef_goods_update_time.desc())
            .all()
        )
        imgs_info = []
        for g in goods_list:
            img = {}
            urls = json.loads(g.sdef_goods_thumbnail)
            if len(urls) > 2:
                img["img_url"] = urls[2]
                img["goods_url"] = "/mall/detail/" + g.sdef_goods_id
                imgs_info.append(img)
        imgs_info = imgs_info[0:nums]
        session.close()
        return imgs_info

    async def get(self):
        open_id = await self.get_open_id()
        is_pad = True if re.match(r"^\d+$", open_id) else False
        nums = int(self.get_parameter("nums", 3))

        # 通用参数
        page_index = int(self.get_parameter("page_index", 0))
        page_size = int(self.get_parameter("page_size", 10))
        # 检查参数的合法性
        ApiHelper.inspect_common_params(page_index, page_size)
        page_start = page_index * page_size
        t = self.get_parameter("t", None)
        lng = float(self.get_parameter("lng", 0))
        lat = float(self.get_parameter("lat", 0))

        class Goods(object):
            pass

        class Carts(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "sdet_cart", "model": Carts},
            ]
        )

        filters = dict(
            sdef_goods_status=1,
            sdef_goods_is_visible=1,
            sdef_goods_is_delete=0,
            sdef_goods_factory_uid=config.FACTORY_UID,
        )

        # 供应商平台所属用户只列出该供应商的商品
        # supplier_id = UserHelper.get_user_supplier_id(open_id)
        # if supplier_id:
        #     filters["sdef_goods_supplier"] = supplier_id

        if t:
            # 拼柜商品列表
            goods_array = (
                session.query(Goods)
                .filter_by(**filters)
                .filter(Goods.sdef_goods_pin_price > 0)
                .order_by(
                    Goods.sdef_goods_order_num.asc(), Goods.sdef_goods_price.asc()
                )[page_start : page_start + page_size]
            )
        else:
            goods_array = (
                session.query(Goods)
                .filter_by(**filters)
                .order_by(
                    Goods.sdef_goods_order_num.asc(), Goods.sdef_goods_price.asc()
                )[page_start : page_start + page_size]
            )

        cart_array = session.query(Carts).filter_by(sdef_cart_device_id=open_id).all()
        cart_count = 0
        if len(cart_array) > 0:
            cart_goods = json.loads(cart_array[0].sdef_cart_goods)
            for g in cart_goods:
                cart_count = cart_count + g["count"]

        goods_list = []
        if len(goods_array) > 0:
            for g in goods_array:
                goods = {}
                goods["goods_id"] = g.sdef_goods_id
                goods["goods_thumbnail"] = json.loads(g.sdef_goods_thumbnail)
                goods["goods_name"] = g.sdef_goods_name
                goods["goods_price"] = str(g.sdef_goods_price.quantize(Decimal("0.00")))
                goods["goods_member_price"] = str(
                    g.sdef_goods_member_price.quantize(Decimal("0.00"))
                )
                goods["goods_count"] = g.sdef_goods_count
                goods["unit"] = ApiHelper.get_unit(g.sdef_goods_unit)
                goods["pin_price"] = (
                    "%.2f" % g.sdef_goods_pin_price if g.sdef_goods_pin_price else None
                )
                goods["list_price"] = (
                    "%.2f" % g.sdef_goods_list_price
                    if g.sdef_goods_list_price
                    else None
                )
                goods["mpq"] = g.sdef_goods_mpq
                goods["video"] = g.sdef_goods_video
                goods_list.append(goods)

        (
            store_id,
            store_name,
            address,
            phone,
            store_lng,
            store_lat,
        ) = UserHelper.get_online_store_info(open_id)
        store_img = f"https://{DOMAIN}/static/img/content/logo-60x60.png"
        if not store_id:
            store_id = 1
            store_name = "莱支好酒" if DOMAIN == "wx.laez9.com" else "莱支红酒"
            address = "广东省深圳市宝安区西乡街道流塘阳光花园2栋115"
            phone = "13534077553"
            store_lng = "113.89033"
            store_lat = "22.582079"

        context = dict(
            text="商城",
            goods_list=goods_list,
            cart_count=cart_count,
            device_id=open_id,
            is_pad=is_pad,
            is_membership=self.is_membership(open_id),
            imgs_info=self.get_imgs(nums),
            store_id=store_id,
            store_name=store_name,
            store_img=store_img,
            address=address,
            phone=phone,
            distance=ApiHelper.geodistance(
                lng, lat, float(store_lng), float(store_lat)
            ),
            apiserver=HOST_NAME,
            site="莱支好酒" if DOMAIN == "wx.laez9.com" else "莱支红酒",
        )

        session.close()
        return self.write(ret_msg(data=context))

    async def post(self):
        open_id = await self.get_open_id()
        action = self.get_parameter("action")
        # 通用参数
        page_index = int(self.get_parameter("page_index", 0))
        page_size = int(self.get_parameter("page_size", 10))
        # 检查参数的合法性
        ApiHelper.inspect_common_params(page_index, page_size)
        page_start = page_index * page_size

        class Carts(object):
            pass

        class Goods(object):
            pass

        class GoodsOrder(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_cart", "model": Carts},
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "sdet_order", "model": GoodsOrder},
            ]
        )

        if action == "add-cart":
            goods_id = self.get_parameter("goods_id")
            count = self.get_parameter("count", None)
            if count is None:
                count = 1
            count = int(count)

            if not (goods_id and re.match("^\d+$", goods_id)):
                session.close()
                logger.error(f"mall: add-cart: 无商品编号或商品编号错误 goods_id={goods_id}")
                return self.write(ret_msg(-1, error_message="商品编号错误"))

            # 检查库存：必须是上架+未删除+库存大于0
            goods = (
                session.query(Goods)
                .filter(Goods.sdef_goods_count > 0)
                .filter_by(
                    sdef_goods_id=goods_id, sdef_goods_status=1, sdef_goods_is_delete=0
                )
                .first()
            )
            if not goods:
                session.close()
                return self.write(ret_msg(-1, error_message="商品库存不足或已下架"))

            # 检查数量是否超出库存
            if count > goods.sdef_goods_count:
                session.close()
                return self.write(ret_msg(-1, error_message="商品库存不足"))

            # 检查是否限购 - 新人礼
            if goods_id == promotion.NEW_CUSTOMER_PROMO_GOODS_ID:
                new_customer_gift_order = (
                session.query(GoodsOrder)
                .filter_by(
                    sdef_order_device_id=open_id,
                    sdef_order_pay_status=1,
                    sdef_order_is_delete=0,
                ).filter(
                    GoodsOrder.sdef_order_goods.contains(goods_id)
                )
                .first()
                )
                if new_customer_gift_order:
                    session.close()
                    return self.write(ret_msg(code=-1, error_message=f"{_goods.sdef_goods_name} 已限购，请勿下单"))

            cart = session.query(Carts).filter_by(sdef_cart_device_id=open_id).first()
            cart_goods = []
            is_exists = False
            if cart:
                is_exists = True
                cart_goods = json.loads(cart.sdef_cart_goods)

                # 检查购物车是否已经有这个商品
                for c in cart_goods:
                    if c.get("id") == goods_id:
                        c["count"] += count
                        c["is_buy"] = 1
                        if c["count"] > goods.sdef_goods_count:
                            session.close()
                            return self.write(ret_msg(-1, error_message="商品库存不足"))
                        # 修改
                        cart_goods_json = json.dumps(cart_goods)
                        session.query(Carts).filter_by(
                            sdef_cart_device_id=open_id
                        ).update({Carts.sdef_cart_goods: cart_goods_json})
                        session.commit()
                        # 计算购物车商品数量
                        cart_count = 0
                        for c in cart_goods:
                            cart_count += c["count"]
                        session.close()
                        return self.write(ret_msg(data=cart_count))

            # 新商品添加进购物车
            cart_goods.append({"id": goods_id, "count": count, "is_buy": 1})
            cart_goods_json = json.dumps(cart_goods)
            if is_exists:
                # 修改
                session.query(Carts).filter_by(sdef_cart_device_id=open_id).update(
                    {Carts.sdef_cart_goods: cart_goods_json}
                )
                session.commit()
            else:
                # 添加购物车
                _cart = Carts()
                _cart.sdef_cart_device_id = open_id
                _cart.sdef_cart_goods = cart_goods_json
                _cart.sdef_cart_update_time = datetime.datetime.now()
                session.add(_cart)
                session.commit()
            # 计算购物车商品数量
            cart_count = 0
            for c in cart_goods:
                cart_count += c["count"]
            session.close()
            return self.write(ret_msg(data=cart_count))

        elif action == "pre-search":
            # 最近关键词，热门关键词，推荐关键词
            data = {
                "searched_keywords": [],
                "hot_keywords": ["PR", "腾塔堡"],
                "recommend_keywords": ["PR", "腾塔堡"],
            }
            return self.write(ret_msg(data=data))

        elif action == "search":
            keyword = self.get_parameter("keyword", None)

            if not keyword:
                session.close()
                logger.error(f"搜索商品: 没有关键词 open_id={open_id}")
                return self.write(ret_msg(-1, error_message="没有搜索关键词"))

            filters = dict(
                sdef_goods_status=1,  # 已上架
                sdef_goods_is_visible=1, # 非隐藏
                sdef_goods_is_delete=0,  # 未删除
                sdef_goods_factory_uid=config.FACTORY_UID,  # 平台UID
            )

            goods_array = (
                session.query(Goods)
                .filter_by(**filters)
                .filter(
                    or_(
                        Goods.sdef_goods_name.ilike(f"%{keyword}%"),  # 名称
                        Goods.sdef_goods_describe.ilike(f"%{keyword}%"),  # 描述
                        Goods.sdef_goods_tag.ilike(f"%{keyword}%"),  # 标签
                    )
                )
                .distinct()
                .order_by(Goods.sdef_goods_price)[page_start : page_start + page_size]
            )

            data = {
                "goods_list": [
                    {
                        "goods_id": g.sdef_goods_id,
                        "goods_name": g.sdef_goods_name,
                        "goods_price": str(
                            g.sdef_goods_price.quantize(Decimal("0.00"))
                        ),
                        "goods_member_price": str(
                            g.sdef_goods_member_price.quantize(Decimal("0.00"))
                        ),
                        "pin_price": "%.2f" % g.sdef_goods_pin_price
                        if g.sdef_goods_pin_price
                        else None,
                        "list_price": "%.2f" % g.sdef_goods_list_price
                        if g.sdef_goods_list_price
                        else None,
                        "goods_count": g.sdef_goods_count,
                        "unit": ApiHelper.get_unit(g.sdef_goods_unit),
                        "mpq": g.sdef_goods_mpq,
                        "video": g.sdef_goods_video,
                        "goods_thumbnail": json.loads(g.sdef_goods_thumbnail),
                    }
                    for g in goods_array
                ]
            }
            session.close()
            return self.write(ret_msg(data=data))

        session.close()
        logger.error(f"mall: 没有指定要求或超出定义范围 open_id={open_id} action={action}")
        return self.write(ret_msg(-1, error_message="没有指定动作要求或超出定义范围"))


class Goods(ApiBaseHandler):
    def data_received(self, chunk):
        pass

    async def get(self):
        open_id = await self.get_open_id()
        goods_type = self.get_parameter("goods_type", 0)

        # 通用参数
        page_index = int(self.get_parameter("page_index", 0))
        page_size = int(self.get_parameter("page_size", 10))
        # 检查参数的合法性
        ApiHelper.inspect_common_params(page_index, page_size)
        page_start = page_index * page_size

        class Goods(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_goods", "model": Goods},
            ]
        )

        filters = dict(
            sdef_goods_status=1,
            sdef_goods_is_visible=1,
            sdef_goods_is_delete=0,
            sdef_goods_factory_uid=config.FACTORY_UID,
        )

        # 供应商平台所属用户只列出该供应商的商品
        # supplier_id = UserHelper.get_user_supplier_id(open_id)
        # if supplier_id:
        #     filters["sdef_goods_supplier"] = supplier_id

        if goods_type:
            filters["sdef_goods_type_"] = goods_type

        goods_array = (
            session.query(Goods)
            .filter_by(**filters)
            .order_by(Goods.sdef_goods_order_num.asc(), Goods.sdef_goods_price.asc())[
                page_start : page_start + page_size
            ]
        )

        goods_list = []
        if len(goods_array) > 0:
            for g in goods_array:
                goods = {
                    "goods_id": g.sdef_goods_id,
                    "goods_thumbnail": json.loads(g.sdef_goods_thumbnail),
                    "goods_name": g.sdef_goods_name,
                    "goods_type": g.sdef_goods_type_,
                    "goods_price": str(g.sdef_goods_price.quantize(Decimal("0.00"))),
                    "goods_member_price": str(
                        g.sdef_goods_member_price.quantize(Decimal("0.00"))
                    ),
                    "goods_count": g.sdef_goods_count,
                    "unit": ApiHelper.get_unit(g.sdef_goods_unit),
                    "pin_price": "%.2f" % g.sdef_goods_pin_price
                    if g.sdef_goods_pin_price
                    else None,
                    "list_price": "%.2f" % g.sdef_goods_list_price
                    if g.sdef_goods_list_price
                    else None,
                    "mpq": g.sdef_goods_mpq,
                    "video": g.sdef_goods_video,
                }
                goods_list.append(goods)
        session.close()
        return self.write(ret_msg(data=goods_list))


class GoodsDetail(ApiBaseHandler):
    def data_received(self, chunk):
        pass

    async def get(self, goods_id):
        view = self.get_parameter("view", None)
        source = self.get_parameter("source", None)
        is_wechat = self.is_in_wechat()

        if view:
            logger.debug("查看者" + view)
            ret = None
        else:
            ret = await self.get_open_id()

        open_id = ret
        if open_id:
            is_pad = True if re.match(r"^\d+$", open_id) else False
        else:
            is_pad = True

        class Goods(object):
            pass

        class UserAddress(object):
            pass

        class Carts(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "sdet_address", "model": UserAddress},
                {"db_table": "sdet_cart", "model": Carts},
            ]
        )
        _goods = session.query(Goods).filter_by(sdef_goods_id=goods_id).first()
        if not _goods:
            logger.error(f"商品详情：商品不存在 goods_id={goods_id}")
            return self.write(ret_msg(-1, error_message=f"商品不存在！"))

        # 计算购物车数量
        cart_array = session.query(Carts).filter_by(sdef_cart_device_id=open_id).all()
        cart_count = 0
        if len(cart_array) > 0:
            cart_goods = json.loads(cart_array[0].sdef_cart_goods)
            filter = dict(sdef_goods_status=1, sdef_goods_is_delete=0)
            for g in cart_goods:
                filter["sdef_goods_id"] = g["id"]
                goods = (
                    session.query(Goods)
                    .filter(Goods.sdef_goods_count > 0)
                    .filter_by(**filter)
                    .first()
                )
                if not goods:
                    continue
                cart_count = cart_count + g["count"]

        # 获取收货地址
        default_address = AddressHelper.get_default(open_id)
        use_address = AddressHelper.get_use(open_id)
        db = mongodb_util.db
        address = None
        if use_address:
            logger.debug("使用地址，address_id=%s" % use_address["address_id"])
            address = (
                session.query(UserAddress)
                .filter_by(sdef_address_id=use_address["address_id"])
                .first()
            )
        elif default_address:
            address = (
                session.query(UserAddress)
                .filter_by(sdef_address_id=default_address["address_id"])
                .first()
            )
        else:
            result = db.sdec_address.find(
                {"user_id": open_id, "is_delete": False}
            ).sort("update_time", pymongo.DESCENDING)
            for a in result:
                address = (
                    session.query(UserAddress)
                    .filter_by(sdef_address_id=a["address_id"])
                    .first()
                )
                break
            # 如果酒柜没有设置地址，就取主人手机设置的地址
            if (not address) and is_pad:
                master_open_id = self.get_device_master_open_id(open_id)
                if master_open_id:
                    default_address = AddressHelper.get_default(master_open_id)
                    if default_address:
                        address = (
                            session.query(UserAddress)
                            .filter_by(sdef_address_id=default_address["address_id"])
                            .first()
                        )
                    else:
                        # 尝试获取第一个地址
                        address = (
                            session.query(UserAddress)
                            .filter_by(
                                sdef_address_device_id=master_open_id,
                                sdef_address_is_del=0,
                            )
                            .order_by(UserAddress.sdef_address_id.desc())
                            .first()
                        )
                    AddressHelper.add(
                        open_id,
                        address.sdef_address_name,
                        address.sdef_address_phone,
                        address.sdef_address_province,
                        address.sdef_address_city,
                        address.sdef_address_county,
                        address.sdef_address_detail,
                        address.sdef_address_id,
                        is_default=True,
                    )
        if address:
            address_dict = dict(
                province=address.sdef_address_province,
                city=address.sdef_address_city,
                county=address.sdef_address_county,
                detail=address.sdef_address_detail,
                name=address.sdef_address_name,
                phone=address.sdef_address_phone,
            )

        goods_dict = dict(
            goods_name=_goods.sdef_goods_name,
            goods_describe=_goods.sdef_goods_describe,
            goods_price=str(_goods.sdef_goods_price.quantize(Decimal("0.00"))),
            goods_member_price=str(
                _goods.sdef_goods_member_price.quantize(Decimal("0.00"))
            ),
            goods_pin_price=str(_goods.sdef_goods_pin_price.quantize(Decimal("0.00"))),
            goods_id=_goods.sdef_goods_id,
            goods_count=_goods.sdef_goods_count,
            pin_price="%.2f" % _goods.sdef_goods_pin_price
            if _goods.sdef_goods_pin_price
            else None,
            list_price="%.2f" % _goods.sdef_goods_list_price
            if _goods.sdef_goods_list_price
            else None,
            goods_img_intro=json.loads(_goods.sdef_goods_img_intro),
            goods_thumbnail=json.loads(_goods.sdef_goods_thumbnail),
            goods_imgs=json.loads(_goods.sdef_goods_img),
            unit=ApiHelper.get_unit(_goods.sdef_goods_unit),
            mpq=_goods.sdef_goods_mpq,
            video=_goods.sdef_goods_video,
            goods_sold=_goods.sdef_goods_sold,
            balance_rate=_goods.sdef_goods_balance_rate,
            goods_tag=_goods.sdef_goods_tag,
            is_trial=UserHelper.is_eligible_for_trial(open_id, goods_id),
            is_gift=UserHelper.is_gift(goods_id),
        )

        context = dict(
            text="商品详情",
            goods=goods_dict,
            address=address_dict if address else None,
            membership_goods_id=config.MEMBERSHIP_GOODS_ID,
            is_membership=self.is_membership(open_id),
            open_id=open_id,
            device_id=open_id,
            cart_count=cart_count,
            view=view,
            source=source,
            is_wechat=is_wechat,
            is_pad=is_pad,
            is_pingui=UserHelper.is_have_pingui_power(open_id),
        )
        session.close()
        return self.write(ret_msg(data=context))


class LastModified(ApiBaseHandler):
    """返回商品表最后修改时间戳，前端据此判断是否需要刷新展示内容"""

    async def get(self):
        class Goods(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_goods", "model": Goods},
            ]
        )
        filters = dict(sdef_goods_factory_uid=config.FACTORY_UID)
        new_goods = (
            session.query(Goods)
            .filter_by(**filters)
            .order_by(Goods.sdef_goods_update_time.desc())
            .all()[0]
        )
        new_date = new_goods.sdef_goods_update_time
        timestamp = time.mktime(new_date.timetuple())
        redis = redis_util.client
        last_time = redis.get("last_goods_timestamp")
        if not last_time or (
            last_time and float(last_time.decode("utf-8")) < timestamp
        ):
            redis.set("last_goods_timestamp", timestamp)
        context = dict(
            timestamp=timestamp,
        )
        session.close()
        return self.write(ret_msg(data=context))


class ImageInfo(ApiBaseHandler):
    async def get(self):
        nums = int(self.get_parameter("nums", 3))

        class Goods(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_goods", "model": Goods},
            ]
        )
        goods_list = (
            session.query(Goods)
            .filter_by(
                sdef_goods_status=1,
                sdef_goods_is_delete=0,
                sdef_goods_factory_uid=config.FACTORY_UID,
            )
            .order_by(Goods.sdef_goods_update_time.desc())
            .all()
        )
        imgs_info = []
        for g in goods_list:
            img = {}
            urls = json.loads(g.sdef_goods_thumbnail)
            if len(urls) > 2:
                img["img_url"] = urls[2]
                img["goods_url"] = "/mall/detail/" + g.sdef_goods_id
                imgs_info.append(img)
        imgs_info = imgs_info[0:nums]
        session.close()
        return self.finish(ret_msg(data=imgs_info))